from PIL import Image

def resize_image(img,target_width=384):
    
    # 计算等比高度
    width_percent = target_width / float(img.size[0])
    height = int(float(img.size[1]) * float(width_percent))
    # 使用双三次插值保持清晰度
    resized_img = img.resize((target_width, height), Image.Resampling.BICUBIC)
    return resized_img

def dither_image(input_path, output_path):
    img = Image.open(input_path).convert("L")  # 转灰度
    img = resize_image(img)
    pixels = img.load()
    width, height = img.size

    for y in range(height):
        for x in range(width):
            old_pixel = pixels[x, y]
            new_pixel = 0 if old_pixel < 128 else 255
            pixels[x, y] = new_pixel
            quant_error = old_pixel - new_pixel

            # 误差扩散（Floyd-Steinberg）
            if x < width - 1:
                pixels[x+1, y] = min(255, max(0, pixels[x+1, y] + quant_error * 7//16))
            if y < height - 1:
                if x > 0:
                    pixels[x-1, y+1] = min(255, max(0, pixels[x-1, y+1] + quant_error * 3//16))
                pixels[x, y+1] = min(255, max(0, pixels[x, y+1] + quant_error * 5//16))
                if x < width - 1:
                    pixels[x+1, y+1] = min(255, max(0, pixels[x+1, y+1] + quant_error * 1//16))

    img.save(output_path, format="BMP", bits=1)
    return img

# 添加函数：将处理后的图像转换为打印机可用的字节数组
def convert_to_printer_bytes(image):
    width, height = image.size
    bytes_per_row = width // 8
    printer_data = []
    
    # 将图像转换为numpy数组以便处理
    import numpy as np
    img_array = np.array(image)
    
    for y in range(height):
        row_data = []
        for x in range(0, width, 8):
            byte_val = 0
            for bit in range(8):
                if x + bit < width:
                    # 在二值图像中，0表示黑色，255表示白色
                    pixel = img_array[y, x + bit]
                    # 如果是黑色像素，则设置对应位
                    if pixel == 0:
                        byte_val |= (1 << (7 - bit))
            row_data.append(byte_val)
        printer_data.append(row_data)
    
    return printer_data, height, bytes_per_row
    
# 修改函数：将图像数据发送到串口并读取返回数据
def send_to_printer(image, port='COM15', baudrate=115200):
    import serial
    import time
    import threading
    
    printer_data, rows, bytes_per_row = convert_to_printer_bytes(image)
    stop_thread = False
    
    # 定义接收线程函数
    def receive_data():
        while not stop_thread:
            try:
                if ser.in_waiting > 0:
                    response = ser.read(ser.in_waiting)
                    print(f"打印机返回数据: {response.decode('utf-8',errors='ignore')}")
                time.sleep(0.01)  # 短暂休眠，避免CPU占用过高
            except Exception as e:
                print(f"接收数据错误: {e}")
                break
    
    try:
        # 打开串口
        ser = serial.Serial(port, baudrate, timeout=1)
        print(f"串口已打开: {port}, 波特率: {baudrate}")
        
        # 启动接收线程
        receive_thread = threading.Thread(target=receive_data)
        receive_thread.daemon = True
        receive_thread.start()
        
        ser.write(bytearray([0x7b,0x01,0x00,0x7a]))
        time.sleep(1.5)
        # 发送每一行数据
        for row_index, row in enumerate(printer_data):
            # 一次发送整行数据
            ser.write(bytes(row))
            
            # 每10行打印一次进度
            if (row_index + 1) % 10 == 0:
                print(f"进度: {row_index+1}/{rows} 行，每行{bytes_per_row}字节")
            
            # 等待一小段时间，控制发送速率
            time.sleep(0.05)
        
        # 发送完成后等待一段时间，确保所有返回数据都被接收
        print(f"发送完成: {rows}行数据，每行{bytes_per_row}字节")
        ser.write(bytearray([0x7b,0x02,0x00,0x7a]))
        time.sleep(1)
        
        # 停止接收线程
        stop_thread = True
        receive_thread.join(timeout=1)
        
        # 关闭串口
        ser.close()
        
    except Exception as e:
        print(f"串口通信错误: {e}")
        stop_thread = True  # 确保线程停止



#img = dither_image("C:\\Users\\xiao\\Pictures\\Camera Roll/22333.jpg", "C:\\Users\\xiao\\Pictures\\Camera Roll/dithered.bmp")
#img = dither_image("C:\\Users\\xiao\\Pictures\\Camera Roll/icheima.bmp", "C:\\Users\\xiao\\Pictures\\Camera Roll/dithered_icheima.bmp")
#img = dither_image("订单_2025050613231518.png", "dithered_icheima.bmp")
#send_to_printer(img,port="COM3")
if __name__ == "__main__":

    img = dither_image("icheima_logo.bmp", "dithered_icheima.bmp")
    send_to_printer(img,port="COM6")